<template>
  <Drawer v-bind="getBindValues" @close="onClose">
    <slot>
      <div>test</div>
    </slot>
    <template #footer v-if="showFooter || $slots.footer">
      <DrawerFooter v-bind="getProps" @close="onClose" @ok="handleOk">
        <template
          #[item]="data"
          v-for="item in Object.keys($slots).filter(item =>
            footerSlots.includes(item)
          )"
        >
          <slot :name="item" v-bind="data || {}"></slot>
        </template>
      </DrawerFooter>
    </template>
  </Drawer>
</template>

<script lang="ts">
import type { DrawerInstance, DrawerProps } from './typing'
import { Drawer } from 'ant-design-vue'
import {
  defineComponent,
  ref,
  unref,
  getCurrentInstance,
  computed,
  toRaw,
  nextTick,
  watch
} from 'vue'
import DrawerFooter from './components/DrawerFooter.vue'
import { basicProps } from './props'
import { deepMerge } from '@/utils'
import { isFunction } from '@/utils/is'

export default defineComponent({
  name: 'BaiscDrawer',
  components: { Drawer, DrawerFooter },
  inheritAttrs: false,
  props: basicProps,
  emits: ['update:visible', 'register', 'visible-change', 'close', 'ok'],
  setup(props, { emit, attrs, slots }) {
    const visibleRef = ref(false)
    const propsRef = ref<Partial<Nullable<DrawerProps>>>(null)

    const footerSlots = ['footer']

    // const { t } = useI18n()

    const drawerInstance: DrawerInstance = {
      setDrawerProps: setDrawerProps,
      emitVisible: undefined
    }

    const instance = getCurrentInstance()

    instance && emit('register', drawerInstance, instance.uid)

    function setDrawerProps(props: Partial<DrawerProps>): void {
      // Keep the last setDrawerProps
      propsRef.value = deepMerge(unref(propsRef) || ({} as any), props)

      if (Reflect.has(props, 'visible')) {
        visibleRef.value = !!props.visible
      }
    }

    const getMergeProps = computed((): DrawerProps => {
      return deepMerge(toRaw(props), unref(propsRef))
    })

    const getProps = computed((): DrawerProps => {
      const opt = {
        placement: 'right',
        ...unref(attrs),
        ...unref(getMergeProps),
        visible: unref(visibleRef)
      }
      return opt as DrawerProps
    })

    watch(
      () => props.visible,
      (newVal, oldVal) => {
        if (newVal !== oldVal) visibleRef.value = newVal
      },
      { deep: true }
    )

    watch(
      () => visibleRef.value,
      visible => {
        nextTick(() => {
          emit('visible-change', visible)
          instance && drawerInstance.emitVisible?.(visible, instance.uid)
        })
      }
    )

    async function onClose(e: Recordable) {
      const { closeFunc } = unref(getProps)
      emit('close', e)
      if (closeFunc && isFunction(closeFunc)) {
        const res = await closeFunc()
        visibleRef.value = !res
        return
      }
      visibleRef.value = false
    }

    const getBindValues = computed((): DrawerProps => {
      return {
        ...attrs,
        ...unref(getProps)
      }
    })

    function handleOk() {
      emit('ok')
    }

    return { getBindValues, getProps, onClose, handleOk, footerSlots }
  }
})
</script>